package org.tema.ejb;

import java.sql.Date;
import java.util.Collection;
import java.util.HashSet;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.tema.entities.Product;
import org.tema.entities.Report;
import org.tema.entities.TestCase;
import org.tema.entities.TestPlan;
import org.tema.entities.User;

/**
 * Session Bean implementation class TestPlanBean
 */
@Stateless
public class TestPlanBean implements TestPlanBeanLocal {
	
	@PersistenceContext
	private EntityManager entityManager;
	
	@EJB
	ProductBeanLocal productBean;
	
	@EJB
	UserBeanLocal userBean;
	
	@EJB
	TestSpecBeanLocal specificationBean;
	
	@EJB
	TestCaseBeanLocal testCaseBean;

    public TestPlanBean() {
       
    }
    
 //Bean CRUD methods
    public TestPlan addTestPlan(Collection <String> testCasesToAdd, String productName, String summary, String testCycle, double planedTime, Date sDate, Date eDate, Date mDate, Date cDate, String creatorUser ){
    	//implement a function to calculate the actual execution time
    	//calculate current Date and actual execution time, from the start execution till current time.
    	
    	//Query query = entityManager.createQuery(" CURRENT_DATE() ");
    	//Date cDate = (Date) query.getSingleResult();
    	//problem with conversion from set to list
    	
    	HashSet <TestCase>  testCaseSet= new HashSet <TestCase> ( );
    	TestPlan testPlan = new TestPlan();
    	User currentUser = userBean.findUserByName(creatorUser);
    	testPlan.setSummary( summary );
    	testPlan.setTestCycle(testCycle);
    	testPlan.setPlannedExecutionTime(planedTime);
    	testPlan.setStartExecution(sDate);
    	testPlan.setEndExecution(eDate);
    	testPlan.setCreationDate(cDate);
    	testPlan.setModificationDate(mDate);
    	testPlan.setCreator(currentUser);
    	Product product = productBean.findProductByName(productName);
    	for (String testCase : testCasesToAdd){
    		TestCase tc = testCaseBean.findTestCaseBySummary(testCase);
    		testCaseSet.add(tc);
    	}
    	/*
    	 for(Product product : productBean.findAllProducts() ){
	    		productList.add( new SelectItem(product.getName() ) );
	    	}
    	 */
    	testPlan.setTestCaseSet(testCaseSet);
    	testPlan.setProduct(product);
		entityManager.persist(testPlan);
		return testPlan;
    }
    

    
	public TestPlan  updateTestPlan(TestPlan testPlan, String modifier){
    	User currentUser = userBean.findUserByName(modifier);
    	testPlan.setModifier(currentUser);
		entityManager.merge(testPlan);
	    return testPlan;
	}
	
	public TestPlan undoTestPlanChanges(TestPlan testPlan){
	    entityManager.refresh(entityManager.merge(testPlan));
	    return testPlan;
	}
	
	public void deleteTestPlan(TestPlan testPlan){
		entityManager.remove(entityManager.merge(testPlan));
		
	}

	@SuppressWarnings("unchecked")
	public Collection <TestPlan> findAllTestPlans(){
		Query query = entityManager.createQuery(" SELECT c FROM TestPlan c ");
		return (Collection <TestPlan>) query.getResultList();
	}

	//////Report related methods////////////////////////////////////////////////////
    //returns the man hours worked
    @SuppressWarnings({ "deprecation", "unchecked" })
	public double calculateActualExecTime( TestPlan tPlan){//code the actual function
    	double actualExeTime = 0;
    	Collection <TestCase> testCaseList = (Collection <TestCase>) tPlan.getTestCaseSet();
    	for (TestCase tc : testCaseList) {
    		actualExeTime = actualExeTime + tc.getExecutionTime();
    	}
    	return actualExeTime;
    
    }
	
	public Report generateReport( TestPlan tPlan){
		Report report = new Report();
		TestPlan plan = this.findTestPlanById(tPlan.getId());
		double failRatio;
		double passRatio;
		int countPassedCases = 0;
		int countFailedCases = 0;
		int countBlockedCases = 0;
		int countUnexecuteCases= 0;
		int countObsolete = 0;
		int allTC = plan.getTestCaseSet().size();
		for (TestCase tc : plan.getTestCaseSet()){
			//count status
			switch(tc.getStatus()){
			case PASSED : countPassedCases++ ; break;
			case FAILED : countFailedCases++ ; break;
			case BLOCKED : countBlockedCases++; break;
			case OBSOLETE: countObsolete++ ; break;
			case NOT_TESTED: countUnexecuteCases++; break;
			}
			//count 
		}
		report.setPassed(countPassedCases);
		report.setFailed(countFailedCases);
		report.setBlocked(countBlockedCases);
		report.setNotExecuted(countUnexecuteCases);
		report.setActualExecTime( this.calculateActualExecTime(plan) );
		if( allTC != 0 ){
			failRatio = countFailedCases/allTC;
			passRatio = countPassedCases/allTC;
		}
		else {
			failRatio=0;
			passRatio=0;
		}
		report.setFailRatio(failRatio);
		report.setPassRatio(passRatio);
		report.setPlan(plan);
		report.setPlannedExecTime( plan.getPlannedExecutionTime() );
		entityManager.persist(report);
		return report;
	}
	//////////////////////report related methods///////////////////////////////
	
	
	
	//add searches for test plans
	public TestPlan findTestPlanById( int id ){
		Query query;
		TestPlan tp;
		try{
			query = entityManager.createQuery(" SELECT c FROM TestPlan c WHERE c.id = :id  ");
			query.setParameter("id", id);
			tp =( TestPlan ) query.getSingleResult();
		}
		catch (NoResultException e) {
			throw new IllegalArgumentException("no test plan  with id '" + id + "'");
		}
		return tp;
	}
	
	@SuppressWarnings("unchecked")
	public TestPlan findTestPlanBySummary( String summary ){
		Query query;
		TestPlan tp;
		try{
			//summary = summary.concat("%");
			query = entityManager.createQuery(" SELECT c FROM TestPlan c WHERE c.summary = :summary  ");
			query.setParameter("summary", summary);
			tp =  ( TestPlan ) query.getSingleResult();
		}
		catch (NoResultException e) {
			throw new IllegalArgumentException("no test plan  with summary '" + summary + "'");
		}
		return tp;
	}
	
	@SuppressWarnings("unchecked")
	public Collection <TestPlan> findTestPlansBySummary( String summary ){
		Query query;
		Collection <TestPlan> tp;
		summary = summary.concat("%");
		query = entityManager.createQuery(" SELECT c FROM TestPlan c WHERE c.summary LIKE :summary  ");
		query.setParameter("summary", summary);
		tp =  (Collection <TestPlan> ) query.getResultList();
		return tp;
	}
	
	@SuppressWarnings("unchecked")
	public Collection <TestPlan > findTestPlanByProductName( String productName ){
		Product product = productBean.findProductByName( productName );
		Collection <TestPlan> testPlans = product.getPlanSet();
		return (Collection <TestPlan>) testPlans;
	}

	@SuppressWarnings("unchecked")
	public Collection <TestPlan> findTestPlanByProductId( int productId ){
		Product product = productBean.findProductById(productId);
		Collection <TestPlan> testPlans = product.getPlanSet();
		return  testPlans;
	}
	

	@SuppressWarnings("unchecked")
	public Collection <TestPlan> findTestPlanByCDate( Date cDate ){
		Query query = entityManager.createQuery(" SELECT c FROM TestPlan c WHERE c.creationDate = :creationDate ");
		query.setParameter("creationDate", cDate);
		return  ( Collection <TestPlan> ) query.getResultList() ;
	}
	
	
	@SuppressWarnings("unchecked")
	public Collection <TestPlan> findTestPlanByMDate( Date mDate ){
		Query query = entityManager.createQuery(" SELECT c FROM TestPlan c WHERE c.modificationDate = :modificationDate ");
		query.setParameter("modificationDate", mDate);
		return  ( Collection < TestPlan >  ) query.getResultList();
	}
	
	
	
}
